/**
 * 版权所有，侵权必究！
 */

package com.commons.tools.utils;

import org.apache.commons.lang3.*;
import org.joda.time.LocalDate;
import org.joda.time.*;
import org.joda.time.format.*;

import java.text.*;
import java.time.*;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.LocalTime;
import java.time.temporal.*;
import java.util.*;
import java.util.regex.*;

/**
 * 日期处理工具类
 *
 * @author
 * @since 1.0.0
 */
public class DateUtils {
    /**
     * 时间格式(yyyy-MM-dd)
     */
    public final static String DATE_PATTERN = "yyyy-MM-dd";
    /**
     * 时间格式(yyyy-MM-dd HH:mm:ss)
     */
    public final static String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
    /**
     * 时间格式(HH:mm:ss)
     */
    public final static String DATE_HOUR_PATTERN = "HH:mm:ss";
    /**
     * 时间格式(yyyy-MM-dd HH:mm:ss)
     */
    public final static String DATE_MONTH_PATTERN = "yyyy-MM";
    /**
     * 时间格式(yyyy)
     */
    public final static String DATE_YEAR_PATTERN = "yyyy";
    /**
     * 时间格式(yyyyMM)
     */
    public final static String DATE_YEARMONTH_PATTERN = "yyyyMM";
    /**
     * 时间格式(yyyyMMdd)
     */
    public final static String DATE_YEARMONTHDAY_PATTERN = "yyyyMMdd";
    /**
     * 时间格式(yyyyMMdd HH)
     */
    public final static String DATE_TIME_HOUR_PATTERN = "yyyy-MM-dd HH";
    /**
     * 时间格式(HH)
     */
    public final static String HOUR_PATTERN = "HH";
    /**
     * 时
     */
    public final static String HOUR = "小时";
    /**
     * 分
     */
    public final static String MINUTE = "分钟";
    /**
     * 秒
     */
    public final static String SECOND = "秒";

    /**
     * 日期格式化 日期格式为：yyyy-MM-dd
     *
     * @param date 日期
     * @return 返回yyyy-MM-dd格式日期
     */
    public static String format(Date date) {
        return format(date, DATE_PATTERN);
    }

    /**
     * 获取过去30天的开始时间
     * @return
     */
    public static String lastThirty() {
        Calendar now = Calendar.getInstance();
        now.add(Calendar.DAY_OF_MONTH, -30);
        String endDate = new SimpleDateFormat(DATE_PATTERN).format(now.getTime());
        return endDate  + " 00:00:00";
    }

    /**
     * 获取过去7天的开始时间
     * @return
     */
    public static String lastSeven() {
        Calendar now = Calendar.getInstance();
        now.add(Calendar.DAY_OF_MONTH, -7);
        String endDate = new SimpleDateFormat(DATE_PATTERN).format(now.getTime());
        return endDate  + " 00:00:00";
    }
    /**
     * 获取过去1天的开始时间
     * @return
     */
    public static String lastOne() {
        Calendar now = Calendar.getInstance();
        now.add(Calendar.DAY_OF_MONTH, -1);
        String endDate = new SimpleDateFormat(DATE_PATTERN).format(now.getTime());
        return endDate + " 00:00:00";
    }

    /**
     * LocalDateTime 转字符串
     * @param dateTime LocalDateTime
     * @return 字符串
     */
    public static String localDateToStr(LocalDateTime dateTime) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern(DATE_TIME_PATTERN);
        LocalDateTime time = dateTime;
        return df.format(time);
    }

    /**
     * LocalDateTime 和字符串时间比较，格式必须一致
     * @param dateTime LocalDateTime
     * @param time 字符串时间
     * @return 大于等于
     */
    public static Boolean ge(LocalDateTime dateTime, String time) {
        return localDateToStr(dateTime).compareTo(time) >= 0;
    }

    /**
     * LocalDateTime 和字符串时间比较，格式必须一致
     * @param dateTime LocalDateTime
     * @param time 字符串时间
     * @return 小于等于
     */
    public static Boolean le(LocalDateTime dateTime, String time) {
        return localDateToStr(dateTime).compareTo(time) <= 0;
    }

    /**
     * 日期格式化 日期格式为：yyyy-MM-dd
     *
     * @param date    日期
     * @param pattern 格式，如：DateUtils.DATE_TIME_PATTERN
     * @return 返回yyyy-MM-dd格式日期
     */
    public static String format(Date date, String pattern) {
        if (date != null) {
            SimpleDateFormat df = new SimpleDateFormat(pattern);
            return df.format(date);
        }
        return null;
    }

    /**
     * 获取当前时间距离零点时间
     * @param currentDate 当前时间
     * @return 距离时间
     */
    public static Integer getRemainSecondsOneDay(Date currentDate) {
        //使用plusDays加传入的时间加1天，将时分秒设置成0
        LocalDateTime midnight = LocalDateTime.ofInstant(currentDate.toInstant(),
                ZoneId.systemDefault()).plusDays(1).withHour(0).withMinute(0)
                .withSecond(0).withNano(0);
        LocalDateTime currentDateTime = LocalDateTime.ofInstant(currentDate.toInstant(),
                ZoneId.systemDefault());
        //使用ChronoUnit.SECONDS.between方法，传入两个LocalDateTime对象即可得到相差的秒数
        long seconds = ChronoUnit.SECONDS.between(currentDateTime, midnight);
        return (int) seconds;
    }

    /**
     * 获取两个时间的时间差，返回中文格式
     * @param startTime HH:mm:ss
     * @param endTime HH:mm:ss
     * @return 比如：1小时2分钟2秒
     */
    public static String duration(String startTime, String endTime) {
        Duration between = Duration.between(LocalTime.parse(startTime), LocalTime.parse(endTime));
        long seconds = between.getSeconds();
        if (seconds <= 60) { return seconds + SECOND; }
        else if (seconds > 60 && seconds <= 3600) {
            int minute =  (int)Math.floor((double)seconds / 60);
            long second =  seconds % 60;
            return minute + MINUTE + second + SECOND;
        } else {
            int hour =  (int)Math.floor((double)seconds / 3600);
            final long leftTime = seconds - hour * 3600;
            int minute =  (int)Math.floor((double)leftTime / 60);
            long second =  leftTime % 60;
            return hour + HOUR + minute + MINUTE + second + SECOND;
        }
    }


    /***
     * 判断字符串是否不是yyyy-MM-dd格式
     * @param mes 字符串
     * @return boolean 是否是否不是日期格式
     */
    public static boolean isNqFormat(String mes){
        String format = "([0-9]{4})-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])";
        Pattern pattern = Pattern.compile(format);
        Matcher matcher = pattern.matcher(mes);
        if (matcher.matches()) {
            pattern = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})");
            matcher = pattern.matcher(mes);
            if (matcher.matches()) {
                int y = Integer.valueOf(matcher.group(1));
                int m = Integer.valueOf(matcher.group(2));
                int d = Integer.valueOf(matcher.group(3));
                if (d > 28) {
                    Calendar c = Calendar.getInstance();
                    c.set(y, m-1, 1);
                    //每个月的最大天数
                    int lastDay = c.getActualMaximum(Calendar.DAY_OF_MONTH);
                    return (lastDay < d);
                }
            }
            return false;
        }
        return true;
    }
    /***
     * 判断字符串是否不是yyyyMM格式
     * @param value 字符串
     * @return boolean 是否不是日期格式
     */
    public static boolean isAnInvalidFormat(String value) {
        Date date = null;
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");
            date = sdf.parse(value);
            if (!value.equals(sdf.format(date))) {
                date = null;
            }
        } catch (ParseException ex) {
            ex.printStackTrace();
        }
        return date == null;
    }

    /**
     * 日期解析
     *
     * @param date    日期
     * @param pattern 格式，如：DateUtils.DATE_TIME_PATTERN
     * @return 返回Date
     */
    public static Date parse(String date, String pattern) {
        try {
            return new SimpleDateFormat(pattern).parse(date);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 字符串转换成日期
     *
     * @param strDate 日期字符串
     * @param pattern 日期的格式，如：DateUtils.DATE_TIME_PATTERN
     */
    public static Date stringToDate(String strDate, String pattern) {
        if (StringUtils.isBlank(strDate)) {
            return null;
        }

        org.joda.time.format.DateTimeFormatter fmt = DateTimeFormat.forPattern(pattern);
        return fmt.parseLocalDateTime(strDate).toDate();
    }

    /**
     * 根据周数，获取开始日期、结束日期
     *
     * @param week 周期  0本周，-1上周，-2上上周，1下周，2下下周
     * @return 返回date[0]开始日期、date[1]结束日期
     */
    public static Date[] getWeekStartAndEnd(int week) {
        DateTime dateTime = new DateTime();
        LocalDate date = new LocalDate(dateTime.plusWeeks(week));

        date = date.dayOfWeek().withMinimumValue();
        Date beginDate = date.toDate();
        Date endDate = date.plusDays(6).toDate();
        return new Date[]{beginDate, endDate};
    }

    /**
     * 对日期的【秒】进行加/减
     *
     * @param date    日期
     * @param seconds 秒数，负数为减
     * @return 加/减几秒后的日期
     */
    public static Date addDateSeconds(Date date, int seconds) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusSeconds(seconds).toDate();
    }

    /**
     * 对日期的【分钟】进行加/减
     *
     * @param date    日期
     * @param minutes 分钟数，负数为减
     * @return 加/减几分钟后的日期
     */
    public static Date addDateMinutes(Date date, int minutes) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusMinutes(minutes).toDate();
    }

    /**
     * 对日期的【小时】进行加/减
     *
     * @param date  日期
     * @param hours 小时数，负数为减
     * @return 加/减几小时后的日期
     */
    public static Date addDateHours(Date date, int hours) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusHours(hours).toDate();
    }

    /**
     * 对日期的【天】进行加/减
     *
     * @param date 日期
     * @param days 天数，负数为减
     * @return 加/减几天后的日期
     */
    public static Date addDateDays(Date date, int days) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusDays(days).toDate();
    }

    /**
     * 对日期的【周】进行加/减
     *
     * @param date  日期
     * @param weeks 周数，负数为减
     * @return 加/减几周后的日期
     */
    public static Date addDateWeeks(Date date, int weeks) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusWeeks(weeks).toDate();
    }

    /**
     * 对日期的【月】进行加/减
     *
     * @param date   日期
     * @param months 月数，负数为减
     * @return 加/减几月后的日期
     */
    public static Date addDateMonths(Date date, int months) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusMonths(months).toDate();
    }

    /**
     * 对日期的【年】进行加/减
     *
     * @param date  日期
     * @param years 年数，负数为减
     * @return 加/减几年后的日期
     */
    public static Date addDateYears(Date date, int years) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusYears(years).toDate();
    }

    public static int getQuarterOfYear() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        return calendar.get(Calendar.MONTH) / 3 + 1;
    }

    /**
     * 获取当前月所有日期
     *
     * @author liujc
     * @Date 2021/3/15 9:23
     */
    public static List<String> getMonthDay() {
        List list = new ArrayList();
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        int year = cal.get(Calendar.YEAR);//年份
        int month = cal.get(Calendar.MONTH) + 1;//月份
        int day = cal.getActualMaximum(Calendar.DATE);
        for (int i = 1; i <= day; i++) {
            String aDate = null;
            if (month < 10 && i < 10) {
                aDate = String.valueOf(year) + "-0" + month + "-0" + i;
            }
            if (month < 10 && i >= 10) {
                aDate = String.valueOf(year) + "-0" + month + "-" + i;
            }
            if (month >= 10 && i < 10) {
                aDate = String.valueOf(year) + "-" + month + "-0" + i;
            }
            if (month >= 10 && i >= 10) {
                aDate = String.valueOf(year) + "-" + month + "-" + i;
            }
            list.add(aDate);
        }
        return list;
    }

    /**
     * 获取两个日期间的所有日期
     *
     * @author liujc
     * @Date 2021/3/15 9:24
     */
    public static List<String> getBetweenDates(Date beginDate, Date endDate) {
        List<String> dateList = new ArrayList<String>();
        Calendar tempStart = Calendar.getInstance();
        tempStart.setTime(beginDate);
        while (beginDate.getTime() <= endDate.getTime()) {
            dateList.add(DateUtils.format(beginDate));
            tempStart.add(Calendar.DAY_OF_YEAR, 1);
            beginDate = tempStart.getTime();
        }
        return dateList;
    }

    /**
     * 获取当前年份的所有月份
     *
     * @author liujc
     * @Date 2021/3/15 9:24
     */
    public static List<String> getYearMonth() {
        List list = new ArrayList();
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        int year = cal.get(Calendar.YEAR);//年份
        for (int i = 1; i <= 12; i++) {
            String aDate = "";
            if (i < 10) {
                aDate = String.valueOf(year) + "-0" + i;
            }
            if (i >= 10) {
                aDate = String.valueOf(year) + "-" + i;
            }
            list.add(aDate);
        }
        return list;
    }

    /**
     * 获取当前季度包含的周
     *
     * @author liujc
     * @Date 2021/3/15 10:50
     */
    public static List<String> getQuarterWeeks() {
        List list = new ArrayList();
        Calendar calendar = Calendar.getInstance();
        calendar.setFirstDayOfWeek(Calendar.MONDAY);//设置星期一为一周开始的第一天
        calendar.setTimeInMillis(DateUtils.getCurrentQuarterStartTime().getTime());//获得当前的时间戳
        int weekYear = calendar.get(Calendar.YEAR);//获得当前的年
        int startWeekOfYear = calendar.get(Calendar.WEEK_OF_YEAR);//获得当前日期属于今年的第几周

        calendar.setTimeInMillis(DateUtils.getCurrentQuarterEndTime().getTime());//获得当前的时间戳
        int endWeekOfYear = calendar.get(Calendar.WEEK_OF_YEAR);//获得当前日期属于今年的第几周

        for (int i = startWeekOfYear; i <= endWeekOfYear; i++) {
            if (i < 10) {
                list.add(weekYear + "0" + i);
            } else {
                list.add(weekYear + "" + i);
            }
        }
        return list;
    }

    /**
     * 当前季度的开始时间
     *
     * @return
     */

    public static Date getCurrentQuarterStartTime() {
        Calendar c = Calendar.getInstance();
        int currentMonth = c.get(Calendar.MONTH) + 1;
        Date now = null;
        try {
            if (currentMonth >= 1 && currentMonth <= 3) {
                c.set(Calendar.MONTH, 0);
            } else if (currentMonth >= 4 && currentMonth <= 6) {
                c.set(Calendar.MONTH, 3);
            } else if (currentMonth >= 7 && currentMonth <= 9) {
                c.set(Calendar.MONTH, 4);
            } else if (currentMonth >= 10 && currentMonth <= 12) {
                c.set(Calendar.MONTH, 9);
            }
            c.set(Calendar.DATE, 1);
            now = DateUtils.parse(DateUtils.format(c.getTime()) + " 00:00:00", DateUtils.DATE_TIME_PATTERN);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return now;
    }

    /**
     * 当前季度的结束时间
     *
     * @return
     */

    public static Date getCurrentQuarterEndTime() {
        Calendar c = Calendar.getInstance();
        int currentMonth = c.get(Calendar.MONTH) + 1;
        Date now = null;
        try {
            if (currentMonth >= 1 && currentMonth <= 3) {
                c.set(Calendar.MONTH, 2);
                c.set(Calendar.DATE, 31);
            } else if (currentMonth >= 4 && currentMonth <= 6) {
                c.set(Calendar.MONTH, 5);
                c.set(Calendar.DATE, 30);
            } else if (currentMonth >= 7 && currentMonth <= 9) {
                c.set(Calendar.MONTH, 8);
                c.set(Calendar.DATE, 30);
            } else if (currentMonth >= 10 && currentMonth <= 12) {
                c.set(Calendar.MONTH, 11);
                c.set(Calendar.DATE, 31);
            }
            now = DateUtils.parse(DateUtils.format(c.getTime()) + " 23:59:59", DateUtils.DATE_TIME_PATTERN);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return now;
    }

    /**
     * 获取两个日期间的所有日期（yyyyMM）
     * @param minDate
     * @param maxDate
     * @return
     * @throws java.text.ParseException
     */
    public static List<String> getMonthBetween(String minDate, String maxDate) {
        ArrayList<String> result = new ArrayList<String>();
        SimpleDateFormat sdf = new SimpleDateFormat(DATE_YEARMONTH_PATTERN);// 格式化为年月
        Calendar min = Calendar.getInstance();
        Calendar max = Calendar.getInstance();
        try {
            min.setTime(sdf.parse(minDate));
            min.set(min.get(Calendar.YEAR), min.get(Calendar.MONTH), 1);

            max.setTime(sdf.parse(maxDate));
            max.set(max.get(Calendar.YEAR), max.get(Calendar.MONTH), 2);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        Calendar curr = min;
        while (curr.before(max)) {
            result.add(sdf.format(curr.getTime()));
            curr.add(Calendar.MONTH, 1);
        }

        return result;
    }
}

